home *** CD-ROM | disk | FTP | other *** search
/ Shareware Super Platinum 8 / Shareware Super Platinum 8.iso / mac / PROGTOOL / DMPI.ZIP;1 / DPMI.C next >
Encoding:
C/C++ Source or Header  |  1991-09-09  |  7.2 KB  |  276 lines

  1. /*
  2. DPMI.C -- DPMI functions, plus some undocumented Windows functions that
  3. provide the same functionality, plus several layers of "sugar-coating"
  4. on top of these low-level services, to make them palatable
  5.  
  6. Copyright (c) Ziff Communications, Co.
  7.     PC Magazine * Andrew Schulman
  8. */
  9.  
  10. #include <Windows.h>
  11. #include <dos.h>
  12. #include "dpmi.h"
  13.  
  14. /* are we already in protected mode, running under DPMI? */
  15. BOOL dpmi_present()
  16. {
  17.   asm {
  18.     mov ax, 0x1686;
  19.     int 0x2F;
  20.     not ax;
  21.       }
  22.   return (_AX);
  23. }
  24.  
  25. /* get DPMI kernal version, flags and (?)process number */
  26. void dpmi_version(unsigned *pmaj, unsigned *pmin,
  27.     unsigned *pflags, unsigned *pproc)
  28. {
  29.   unsigned char maj, min, proc;
  30.   unsigned flags;
  31.   asm {
  32.     mov ax, 0x0400;
  33.     int 0x31;
  34.     mov maj, ah;
  35.     mov min, al;
  36.     mov flags, bx;
  37.     mov proc, cl
  38.       }
  39.   *pmaj   = maj;
  40.   *pmin   = min;
  41.   *pflags = flags;
  42.   *pproc  = proc;
  43. }
  44.  
  45. /* Perform a real-mode interrupt from protected mode */
  46. BOOL dpmi_rmode_intr(unsigned intno, unsigned flags,
  47.     unsigned copywords, RMODE_CALL far *rmode_call)
  48. {
  49.   unsigned success;
  50.  
  51.   if (flags) intno |= 0x0100;
  52.   asm {
  53.     push es;
  54.         push di;
  55.     mov ax, 0x0300;     // simulate real-mode interrupt
  56.     mov bx, word ptr intno; // interrupt number, flags
  57.     mov cx, word ptr copywords;    // words to copy from pmode to rmode stack
  58.     les di, dword ptr rmode_call;    // ES:DI = addr of rmode call struct
  59.     int 0x31;        // call DPMI
  60.     pop di;
  61.     pop es;
  62.         jnc short done;         // return TRUE
  63.         mov success, 0;         // return FALSE
  64.       }
  65. done:
  66.   return (success);
  67. }
  68.  
  69. /* Allocates a single protected-mode LDT selector */
  70. unsigned dpmi_sel(void)
  71. {
  72.   unsigned rc=0;
  73.  
  74.   asm {
  75.     xor ax, ax;    // Allocate LDT descriptor
  76.     mov cx, 1;    // allocate just one
  77.     int 0x31;    // call DPMI
  78.         jc short done;
  79.         mov rc, ax;
  80.       }
  81. done:
  82.   return (rc);
  83. }
  84.  
  85. /* set a descriptor for a protected mode selector */
  86. BOOL dpmi_set_descriptor(unsigned pmodesel, DESCRIPTOR far *d)
  87. {
  88.   int success=1; // TRUE
  89.  
  90.   asm {
  91.     push es;
  92.         push di;
  93.     mov ax, 0x000c        // set descriptor
  94.     mov bx, word ptr pmodesel;    // protected mode selector
  95.     les di, dword ptr d;    // descriptor
  96.     int 0x31        // call DPMI
  97.     pop di;
  98.     pop es;
  99.         jnc short done;
  100.         mov success, 0;         // return TRUE
  101.     jmp short done
  102.       }
  103. done:
  104.   return (success);
  105. }
  106.  
  107. /* get the associated descriptor for a protected mode selector */
  108. /*** same as set_desc, except for mov ax, 0x000b .vs. 0x000c ***/
  109. BOOL dpmi_get_descriptor(unsigned pmodesel, DESCRIPTOR far *d)
  110. {
  111.   int success=1;
  112.   asm {
  113.     push es;
  114.     push di;
  115.     mov ax, 0x000b        // get descriptor
  116.     mov bx, word ptr pmodesel;    // protected mode selector
  117.     les di, dword ptr d;    // descriptor
  118.     int 0x31        // call DPMI
  119.     pop di;
  120.     pop es;
  121.     jnc short done;
  122.     mov success, 0;          // return FALSE
  123.       }
  124. done:
  125.   return (success);
  126. }
  127.  
  128. /* free a selector */
  129. BOOL dpmi_sel_free(unsigned pmodesel)
  130. {
  131.   int success=1;
  132.   asm {
  133.     mov ax, 0x0001;     // free LDT descriptor
  134.     mov bx, word ptr pmodesel;    // protected mode selector
  135.     int 0x31;        // call DPMI
  136.     jnc short done;
  137.     mov success, 0;          // return FALSE
  138.       }
  139. done:
  140.   return (success);
  141. }
  142.  
  143. /* layer on top of DPMI and Windows services *******************************/
  144.  
  145. /* allocate a segment of real DOS memory, and return both real and prot segs */
  146. unsigned DOSAllocRealSeg(DWORD bytes, unsigned *ppara, unsigned *psel)
  147. {
  148.   DWORD dw = GlobalDosAlloc(bytes);
  149.   if (dw == NULL)
  150.     return 8;    // insufficient memory
  151.   *ppara = HIWORD(dw);
  152.   *psel = LOWORD(dw);
  153.   return 0;
  154. }
  155.  
  156. /* free DOS segment */
  157. unsigned DOSFreeRealSeg(unsigned sel)
  158. {
  159.     return(GlobalDosFree(sel) != NULL);
  160. }
  161.  
  162. /*
  163.   Use DPMI services to map a real-mode paragraph into protected mode
  164.   address space.  First we get a selector using the DPMI "Allocate
  165.   LDT Descriptors" call (INT 31h, Function 0000h), via our dpmi_sel()
  166.   function.  We then get the descriptor for any old data segment in
  167.   our program so that it can be used as a template of sorts for the
  168.   new descriptor.  This is done with the DPMI "Get Descriptor" call
  169.   (INT 31h, Function 000Bh), via our dpmi_get_descriptor() function.
  170.   We then alter the descriptor to reflect the "rmpara" and "size"
  171.   requested, and finally associate the descriptor with our LDT
  172.   selector, using the DPMI "Set Descriptor" call (INT 31h, Function
  173.   000Ch).  All the user needs, of course, is the selector itself.
  174. */
  175. unsigned DOSMapRealSeg(unsigned rmpara, DWORD size, unsigned far *psel)
  176. {
  177.   DESCRIPTOR d;
  178.   unsigned long addr;
  179.   unsigned sel = dpmi_sel();
  180.   if (! sel)
  181.     return 8;        // insufficient memory
  182.   /* make sure psel is valid */
  183.   //if (! verw(FP_SEG(psel)))
  184.   //      return 490;          // invalid selector error
  185.   /* get descriptor for any data segment */
  186.   dpmi_get_descriptor(FP_SEG(psel), &d);
  187.   d.limit = (unsigned) size - 1;
  188.   addr = ((unsigned long) rmpara) << 4L;
  189.   d.addr_lo = (unsigned) addr;
  190.   d.addr_hi = (unsigned char) (addr >> 16);
  191.   d.reserved = d.addr_xhi = 0;
  192.   dpmi_set_descriptor(sel, &d);
  193.   *psel = sel;
  194.   return 0;            // success
  195. }
  196.  
  197. /* free a protected mode selector */
  198. unsigned DOSFreeSeg(unsigned sel)
  199. {
  200.     return ! dpmi_sel_free(sel);
  201. }
  202.  
  203. /*
  204.   Use undocumented Windows function to retrieve the real-mode equivalent
  205.   to a protected mode pointer.    Of course, we could also have used
  206.   dpmi_get_descriptor() here, but GetSelectorBase() is slightly more
  207.   convenient.  If the base of the selector is above the one-megabyte
  208.   watershed, then there is no real-mode equivalent, so we return NULL.
  209. */
  210. void far *DOSProtToReal(void far *prot)
  211. {
  212.   unsigned long base = GetSelectorBase(FP_SEG(prot));
  213.   if (base > 0xFFFFFL)
  214.     return NULL;    /* not accessible in real mode */
  215.   else
  216.     return MAKEP(base >> 4, (base & 0x0F) + FP_OFF(prot));
  217. }
  218.  
  219. unsigned __0000H = 0; /* undocumented Windows selector */
  220. unsigned mapped = 0; /* keep track of mapped selectors */
  221.  
  222. unsigned get_mapped(void)
  223. {
  224.   return mapped;
  225. }
  226.  
  227. /*
  228.   Map a real-mode pointer into our protected mode address space.
  229.   If the real-mode pointer is in the first 64K of memory, use the
  230.   undocumented Windows selector __0000H.  Otherwise, use DPMI services
  231.   via our DOSMapRealSeg() function, which provides a more convenient
  232.   layer on top of DPMI.  This map_real() function in turn provides a more
  233.   convenient layer on top of DOSMapRealSeg().  Note that DOSMapRealSeg()
  234.   takes a full segment:offset real-mode pointer.
  235. */
  236. void far *map_real(void far *rptr, unsigned long size)
  237. {
  238.   unsigned seg, ofs, sel;
  239.  
  240.   if (! __0000H) /* one time init: get undocumented Windows selector */
  241.     __0000H = LOWORD(GetProcAddress(GetModuleHandle("KERNAL"),"__0000H"));
  242.  
  243.   seg = FP_SEG(rptr);
  244.   ofs = FP_OFF(rptr);
  245.   if ((seg < 0x1000) && ((ofs + size) < 0xFFFF))
  246.     return MAKEP(__0000H, (seg << 4) + ofs);
  247.   if (DOSMapRealSeg(seg, size + ofs, &sel) != 0)
  248.     return 0;
  249.   mapped++;
  250.   return MAKEP(sel, ofs);
  251. }
  252.  
  253. void free_mapped_seg(void far *fp)
  254. {
  255.   unsigned sel = FP_SEG(fp);
  256.   if (sel == __0000H)
  257.     return;
  258.   if (DOSFreeSeg(sel) == 0)
  259.     mapped--;
  260. }
  261.  
  262. #ifdef ENABLE_286
  263. /* use Intel VERW instruction to validate pointers */
  264. unsigned verw(unsigned sel)
  265. {
  266.   asm {
  267.     mov ax, 1;
  268.     verw sel;
  269.     je short ok;
  270.     xor ax, ax;
  271.       }
  272. ok:
  273.   return (_AX);
  274. }
  275. #endif
  276.